<style>
    /* Special styling for type=range and type=color input */
    input.form-control[type="range"],
    input.form-control[type="color"] {
        height: 2.25rem;
    }
    input.form-control.form-control-sm[type="range"],
    input.form-control.form-control-sm[type="color"] {
        height: 1.9375rem;
    }
    input.form-control.form-control-lg[type="range"],
    input.form-control.form-control-lg[type="color"] {
        height: 3rem;
    }
    /* Less padding on type=color */
    input.form-control[type="color"] {
        padding: 0.25rem 0.25rem;
    }
    input.form-control.form-control-sm[type="color"] {
        padding: 0.125rem 0.125rem;
    }
</style>

<script>
    import { idMixin, formMixin, formSizeMixin, formStateMixin } from '../../mixins';
    import { arrayIncludes } from '../../utils/array';
    
    // Valid supported input types
    const TYPES = [
        'text', 'password', 'email', 'number', 'url', 'tel', 'search', 'range', 'color',
        `date`, `time`, `datetime`, `datetime-local`, `month`, `week`
    ];
    
    export default {
        mixins: [idMixin, formMixin, formSizeMixin, formStateMixin],
        render(h) {
            const t = this;
            return h(
                'input',
                {
                    ref: 'input',
                    class: t.inputClass,
                    domProps: { value: t.localValue },
                    attrs: {
                        id: t.safeId(),
                        name: t.name,
                        type: t.localType,
                        disabled: t.disabled,
                        required: t.required,
                        readonly: t.readonly || t.plaintext,
                        placeholder: t.placeholder,
                        autocomplete: t.autocomplete || null,
                        'aria-required': t.required ? 'true' : null,
                        'aria-invalid': t.computedAriaInvalid
                    },
                    on: {
                        input: t.onInput,
                        change: t.onChange
                    }
                }
            );
        },
        data() {
            return {
                localValue: this.value
            }
        },
        props: {
            value: {
                default: null
            },
            type: {
                type: String,
                default: 'text',
                validator: (type) => arrayIncludes(TYPES, type)
            },
            ariaInvalid: {
                type: [Boolean, String],
                default: false
            },
            readonly: {
                type: Boolean,
                default: false
            },
            plaintext: {
                type: Boolean,
                default: false
            },
            autocomplete: {
                type: String,
                default: null
            },
            placeholder: {
                type: String,
                default: null
            },
            formatter: {
                type: Function
            },
            lazyFormatter: {
                type: Boolean,
                default: false
            }
        },
        computed: {
            localType() {
                // We only allow certain types
                return arrayIncludes(TYPES, this.type) ? this.type : 'text';
            },
            inputClass() {
                return [
                    this.plaintext ? 'form-control-plaintext' : 'form-control',
                    // Fix missing width:100% in Bootstrap V4.beta.2
                    this.plaintext ? 'w-100' : '',
                    this.sizeFormClass,
                    this.stateClass
                ];
            },
            computedAriaInvalid() {
                if (!Boolean(this.ariaInvalid) || this.ariaInvalid === 'false') {
                    // this.ariaInvalid is null or false or 'false'
                    return this.computedState === false ? 'true' : null ;
                }
                if (this.ariaInvalid === true) {
                   // User wants explicit aria-invalid=true
                    return 'true';
                }
                // Most likely a string value (which could be 'true')
                return this.ariaInvalid;
            }
        },
        watch:{
            value(newVal, oldVal) {
                if (newVal !== oldVal){
                    this.localValue = newVal;
                }
            },
            localValue(newVal, oldVal) {
                if (newVal !== oldVal){
                    this.$emit('input', newVal);
                }
            }
        },
        methods: {
            format(value, e) {
                if (this.formatter) {
                    const formattedValue = this.formatter(value, e);
                    if (formattedValue !== value) {
                        return formattedValue;
                    }
                }
                return value;
            },
            onInput(evt) {
                const value = evt.target.value;
                if (this.lazyFormatter) {
                    // Update the model with the current unformated value
                    this.localValue = value;
                } else {
                    this.localValue = this.format(value, evt);
                }
            },
            onChange(evt) {
                this.localValue = this.format(evt.target.value, evt);
                this.$emit('change', this.localValue);
            },
            focus() {
                if(!this.disabled) {
                    this.$el.focus();
                }
            }
        }
    };
</script>
